wayland: Check transient loop
authorOlivier Fourdan <ofourdan@redhat.com>
Mon, 14 Dec 2015 15:34:00 +0000 (16:34 +0100)
committerOlivier Fourdan <ofourdan@redhat.com>
Wed, 16 Dec 2015 13:11:11 +0000 (14:11 +0100)
Gdk Wayland backend walks up the transient windows tree, but does not
check for cycles when doing so.

As a result, if two or more windows are transient to each other, the
Wayland gdk backend will enter an infinite loop.

While this is clearly a bug in the application, gtk+/gdk should be more
robust and handle such errors more gracefully.

To avoid looping infinitely at various point in the code, check for a
possible loop when setting the transient relationship and deny the
request to set a window transient for another if that would create a
loop.

Bugzilla: https://bugzilla.gnome.org/show_bug.cgi?id=759299

gdk/wayland/gdkwindow-wayland.c

index 753aac58ec91a485d3a547e1edbfd81782b5c777..077647189229dd9c5897bfc7757299a36be6e297 100644 (file)
@@ -1943,12 +1943,33 @@ gdk_wayland_window_set_startup_id (GdkWindow   *window,
 {
 }
 
+static gboolean
+check_transient_for_loop (GdkWindow *window,
+                          GdkWindow *parent)
+{
+  while (parent)
+    {
+      GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (parent->impl);
+
+      if (impl->transient_for == window)
+        return TRUE;
+      parent = impl->transient_for;
+    }
+  return FALSE;
+}
+
 static void
 gdk_wayland_window_set_transient_for (GdkWindow *window,
                                       GdkWindow *parent)
 {
   GdkWindowImplWayland *impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
+  if (check_transient_for_loop (window, parent))
+    {
+      g_warning ("Setting %p transient for %p would create a loop", window, parent);
+      return;
+    }
+
   if (impl->subsurface)
     unmap_subsurface (window);